home *** CD-ROM | disk | FTP | other *** search
/ PC-X 1997 October / pcx14_9710.iso / swag / delphi.swg / 0241_Lars Koudal.pas < prev   
Encoding:
Pascal/Delphi Source File  |  1997-05-30  |  62.0 KB  |  2,599 lines

  1.  
  2. {
  3. Hello Gayle Davis...
  4.  
  5. I would just like to say how pleased i am with the continuing success of
  6. SWAGS..
  7.  
  8. Below I have included some source of my own. a cd-player, that Iábelieve
  9. is quite nifty, anyways I like it.
  10.  
  11. I would be very pleased and honored if it was included in SWAGS...
  12.  
  13. Yours truly,
  14.  
  15. Lars Koudal
  16.  
  17.  
  18. Denmark, 25th of february 1997
  19.  
  20. A bit of history:
  21. ------------------
  22.    I am one of those people who use my cd-rom drive for playing music while I am working,
  23. eventhough at home I have my left shoulder about 5 inches from the volume knop on my
  24. somewhat larger stereo..
  25.  
  26.    This is a habbit from my good old days where I worked in far less equipped environments.
  27.  
  28.    Nowadays I have what I need in win95... 
  29.  
  30.    Back then though, I was never really satisfied with the cd-players out there. So I wrote
  31. my own... I used a lot of routines grabbed from SWAGS.. (Thanks...) I always intended this
  32. to be only for personal use, but as the program grew larger I felt like I perhaps could
  33. earn some bucks selling the damn thing... THAT was in my young and restless days...
  34.  
  35.    I recently picked up a newer version of swags (haven't done that in more than a year),
  36. and was very thrilled to see how alive this wonderful source of information is..
  37.  
  38.    Therefore I decided to post the small version of my program... If people want it, I will
  39. ofcourse send the full-scale version as well.. That hasn't been fully written yet, but
  40. the damn thing works...
  41.  
  42.    This version is called mini... Probaply due to it's small size (compared to the larger one),
  43. but since it is some years ago, I am not quite sure... :-)
  44.  
  45.    This program uses, as mentioned before, a lot of routines and units from other people. All
  46. grabbed here from swags... Remember! Credit where credit is due!
  47.  
  48.    When you run this damn thing, it pops up on your dos-screen with a single line...
  49. It shows what song is playing, and how long it has been playing...
  50.  
  51.   When you press Pgup, it goes one song up. Guess what happens when you press PgDn! :-)
  52.  
  53.    Press '.' and up comes a list of songs you can pick. Just use up- and down-keys to scroll
  54. and ENTER to make your selection...
  55.  
  56. The whole thing ends when you press ESC...
  57.  
  58.    Try to press F1 from inside the player... I had forgotten this little nifty detail until I tried
  59. it out a few minutes ago...
  60.  
  61.    BTW: If you have a SoundBlaster in your computer, and the routines I use for detecting it
  62. _can_ find it, you can use '+' and '-' to adjust the volume... Pretty nifty...
  63.  
  64.    I used it a lot from inside Turbo Pascal.. I made it a tool, and just pressed Shift-F5,
  65. and there it was... pretty handy... and a lot faster... Ever used QCD (comes with SndB)??
  66. Goddamn slow!
  67.  
  68. (If you can't figure out how to make a new tool in TP, don't bother... put the keyboard down!)
  69.  
  70.  
  71. Well, so much about the past, a bit about the future..:
  72. --------------------------------------------------------
  73.   As I have written, this code is from my novice years. If you for some reason want to contact me,
  74. don't do so if you just want to complain about the lousy code, the many unused variables and the many
  75. work-arounds I did for making the whole thing work. I provide this code to
  76. help novices people out, as I was helped myself some years ago...
  77.  
  78. If you DO decide to contact me, you can e-mail me... (Sorry, left FIDO years ago):
  79.  
  80. lkoudal@usa.net
  81.  
  82.  
  83. Have fun!
  84.  
  85. Yours truly, 
  86.  
  87.  
  88. Lars Koudal.
  89.  
  90.  
  91.  
  92. {Installation notes... Cut and paste the files to their original names, and the compile MINI.PAS... THATS IT!
  93. Play around as much as you like...}
  94.  
  95. {CUT ... Save this as MINI.PAS }
  96. {▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄}
  97.  
  98.  
  99.                                  PROGRAM mini;
  100.  
  101.  
  102. {▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀}
  103.  
  104. {This program is determined that you start it with a color-screen
  105.  If you don't have that, or you do not know how to change it to a monochrome
  106.  screen, don't bother... put the keyboard down...
  107.  
  108.  
  109.  Lars Koudal....
  110.  
  111.  hint: look about 15 lines down, and read the comment...
  112. }
  113.  
  114.  
  115.  
  116. USES
  117. {  effects,
  118. }  CD_Unit,
  119.   CD_Vars,
  120.   DOS,
  121.   CRT,
  122.   TPTimer,
  123.   TCTimer,
  124.   TPBuffer,
  125.   ScanCode;
  126.  
  127. TYPE
  128.   TotPlayRec   = RECORD
  129.                    Frames,
  130.                    Seconds,
  131.                    Minutes,
  132.                    Nada     : Byte;
  133.                  END;
  134. CONST
  135.   TextVidSeg   : Word = $b800;
  136.   vga_segment  = $0A000;
  137.   fade_Delay   = 20;
  138.   vSeg         : Word = $B800;  {change for mono}
  139.  
  140.  
  141.  
  142. VAR
  143.  CurrIndex  : Word;
  144.  ScreenLoc  : Pointer;
  145.  ScrollSize : Word;
  146.  
  147.   vol_time     : longint;
  148.   toslet       : boolean;
  149.   sbfound,
  150.   portok       : Boolean;
  151.   ScrBuf,
  152.   Pdwns        : Word;
  153.   origmode     : word;
  154.   lcv          : Integer;
  155.   temp         : Char;
  156.   a1,
  157.   a2,
  158.   a3           : Byte;
  159.   b1,
  160.   b2,
  161.   b3           : Byte;
  162.   crc          : LongInt;
  163.   cdidstr      : String;
  164.  
  165.   number       : Byte;
  166.   SaveExit     : Pointer;
  167.   TrackInfo    : ARRAY [1..99] OF PAudioTrackInfo;
  168.   I            : Integer;
  169.   CH           : Char;
  170.   SP,
  171.   EP           : LongInt;
  172.   LeadOut,
  173.   StartP,
  174.   TotalPlayTime: LongInt;
  175.   TotPlay      : TotPlayRec;
  176.   place        : LongInt;
  177.   secs,
  178.   pps,
  179.   s            : LongInt;
  180.   Track        : Byte;
  181.   StartTrack,
  182.   EndTrack,
  183.   NumTracks    : Integer;
  184.   Player       : ARRAY [1..100] OF Byte;
  185.   PlayTime     : TotPlayRec;
  186.   result       : Word;
  187.   resultchar   : Char;
  188.   Hi,
  189.   Hi2          : Byte;
  190.   crstyp       : Word;
  191.   arbejder     : Byte;
  192.  
  193.   lvolume,
  194.   rvolume      : Byte; {Volume-control}
  195.  
  196.  
  197.   Scroll_Lock,
  198.   Caps_Lock,
  199.   Num_Lock,
  200.   Ins,
  201.   Alt,
  202.   Ctrl,
  203.   Left_Shift,
  204.   Right_Shift  : Boolean;
  205.   Bios_Keys    : Byte ABSOLUTE $40:$17;
  206.  
  207. Procedure WaitForRetrace; Assembler;
  208. Asm
  209.   Mov  DX, 3DAh
  210.   @Rep1:
  211.   In   AL, DX
  212.   Test AL, 08h
  213.   JZ   @Rep1
  214.   @Rep2:
  215.   In   AL, DX
  216.   Test AL, 08h
  217.   JNZ  @Rep2
  218. End;
  219.  
  220. Function LeadingZero (w : Word) : String;
  221. Var
  222.   s : String;
  223. Begin
  224.   Str (w: 0, s);
  225.   If Length (s) = 1 Then
  226.     s := '0' + s;
  227.   LeadingZero := s;
  228. End;
  229.  
  230.  
  231.  
  232. Function ITOS ( nNum: LongInt; nSpaces: Integer ): String;
  233. Var
  234.    s: ^String;
  235. Begin
  236.   Asm
  237.     mov     sp, BP
  238.     push    ss
  239.     push    Word Ptr @RESULT
  240.   End;
  241.   
  242.   If nSpaces > 0 Then
  243.     Str ( nNum: nSpaces, s^ )
  244.   Else
  245.     Str ( nNum: 0, s^ );
  246. End;
  247.  
  248. Function returnspace (s: String; wantedspace: Byte): String;
  249. Var
  250. i   : Byte;
  251. temp : String;
  252. Begin
  253.   temp := '';
  254.   For i := Length (s) To wantedspace Do
  255.   Begin
  256.     temp := temp + ' ';
  257.   End;
  258.   returnspace := temp;
  259. End;
  260.  
  261. {home-made-calculations of which track is currently being played}
  262. Procedure calctrack;
  263. Var
  264.   Min, Sec: Byte;
  265.   i: Byte;
  266.   svar: Boolean;
  267.   {**************}
  268.   Procedure addtime (m, s: Byte);
  269. Begin
  270.   Min := Min + m;
  271.   Sec := Sec + s;
  272.   If Sec = 60 Then
  273.   Begin
  274.     Min := Min + 1;
  275.     Sec := 0;
  276.   End;
  277.   If Sec > 60 Then
  278.   Begin
  279.     Min := Min + 1;
  280.     Sec := Sec - 60;
  281.   End;
  282. End;
  283. {**************}
  284. {**************}
  285. Procedure bigger (m1, s1, m2, s2: Byte; svar: Boolean);
  286. {calculates whether m1:s1 is bigger than m2:s2:}
  287. Begin
  288.   If (m1 * 60 + s1) > (m2 * 60 + s2) Then svar := True
  289.   Else svar := False;
  290. End;
  291. {**************}
  292.  
  293. Begin
  294.   track := 0;
  295.   Min := 0;
  296.   Sec := 0;
  297.   secs := 0;
  298.   place := Head_Location (1);
  299.  
  300.   For i := starttrack To endtrack Do
  301.   Begin
  302.     If trackinfo [i]^. startpoint < place Then
  303.     Begin
  304.       track := i;
  305.     End;
  306.     If track = 0 Then track := 1;
  307.   End;
  308. End;
  309.  
  310.  
  311. Procedure NoTracks;
  312. Begin
  313.   WriteLn;
  314.   WriteLn ('No tracks on disk');
  315.   WriteLn;
  316.   ExitProc := SaveExit;
  317. End;
  318.  
  319. Procedure Setup;
  320. Begin
  321.   TotalPlayTime := 0;
  322.   LeadOut := AudioDiskInfo. LeadOutTrack;
  323.   
  324.   StartTrack := AudioDiskInfo. LowestTrack;
  325.   EndTrack := AudioDiskInfo. HighestTrack;
  326.   NumTracks := EndTrack - StartTrack + 1;
  327.   
  328.   
  329.   For I := StartTrack To EndTrack Do
  330.   Begin
  331.     Track := I;
  332.     Audio_Track_Info (StartP, Track);
  333.     New (TrackInfo [I] );
  334.     FillChar (TrackInfo [I]^, SizeOf (TrackInfo [I]^), #0);
  335.     TrackInfo [I]^. StartPoint := StartP;
  336.     TrackInfo [I]^. TrackControl := Track;
  337.   End;
  338.  
  339.   For I := StartTrack To EndTrack - 1 Do
  340.     TrackInfo [I]^. EndPoint := TrackInfo [I + 1]^. StartPoint - 1;
  341.  
  342.   TrackInfo [EndTrack]^. EndPoint := AudioDiskInfo. LeadOutTrack - 1;
  343.  
  344.   For I := StartTrack To EndTrack Do
  345.     Move (TrackInfo [I]^. EndPoint, TrackInfo [I]^. Frames, 4);
  346.  
  347.   TrackInfo [StartTrack]^. PlayMin := TrackInfo [StartTrack]^. Minutes;
  348.   TrackInfo [StartTrack]^. PlaySec := TrackInfo [StartTrack]^. Seconds - 2;
  349.  
  350.   For I := StartTrack + 1 To EndTrack Do
  351.   Begin
  352.     EP := (TrackInfo [I]^. Minutes * 60) + TrackInfo [I]^. Seconds;
  353.     SP := (TrackInfo [I - 1]^. Minutes * 60) + TrackInfo [I - 1]^. Seconds;
  354.     EP := EP - SP;
  355.     TrackInfo [I]^. PlayMin := EP Div 60;
  356.     TrackInfo [I]^. PlaySec := EP Mod 60;
  357.   End;
  358.  
  359.   TotalPlayTime := AudioDiskInfo. LeadOutTrack - TrackInfo [StartTrack]^. StartPoint;
  360.   Move (TotalPlayTime, TotPlay, 4);
  361. End;
  362.  
  363.  
  364. Function KeyEnh:  Boolean;
  365. Var
  366.   Enh:  Byte Absolute $0040:$0096;
  367.   
  368. Begin
  369.   KeyEnh := False;
  370.   If (Enh And $10) = $10 Then
  371.     KeyEnh := True;
  372. End;
  373.  
  374. Function InKey (Var SCAN, ASCII:  Byte): Boolean;
  375. Var
  376.   i     :  Integer;
  377.   Shift,
  378.   Ctrl,
  379.   Alt   : Boolean;
  380.   Temp,
  381.   Flag1 : Byte;
  382.   HEXCH,
  383.   HEXRD,
  384.   HEXFL : Byte;
  385.   reg   : Registers;
  386.   
  387. Begin
  388.   If KeyEnh Then
  389.   Begin
  390.     HEXCH := $11;
  391.     HEXRD := $10;
  392.     HEXFL := $12;
  393.   End
  394.   Else
  395.   Begin
  396.     HEXCH := $01;
  397.     HEXRD := $00;
  398.     HEXFL := $02;
  399.   End;
  400.   
  401.   reg. AH := HEXCH;
  402.   Intr ($16, reg);
  403.   i := reg. Flags And fZero;
  404.   
  405.   reg. AH := HEXFL;
  406.   Intr ($16, reg);
  407.   Flag1 := Reg. AL;
  408.   Temp  := Flag1 And $03;
  409.   
  410.   If Temp = 0 Then
  411.     SHIFT := False
  412.   Else
  413.     SHIFT := True;
  414.   
  415.   Temp  := Flag1 And $04;
  416.   If Temp = 0 Then
  417.     CTRL := False
  418.   Else
  419.     CTRL := True;
  420.   
  421.   Temp  := Flag1 And $08;
  422.   If Temp = 0 Then
  423.     ALT  := False
  424.   Else
  425.     ALT  := True;
  426.   
  427.   If i = 0 Then
  428.   Begin
  429.     reg. AH := HEXRD;
  430.     Intr ($16, reg);
  431.     scan  := reg. AH;
  432.     ascii := reg. AL;
  433.     InKey := True;
  434.   End
  435.   Else
  436.     InKey := False;
  437. End;
  438.  
  439. {▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄}
  440. FUNCTION UpStr (CONST s: String): String; ASSEMBLER;
  441.   ASM
  442.     push DS
  443.     lds  SI, s
  444.     les  DI, @result
  445.     lodsb            { load and store length of string }
  446.     stosb
  447.     XOR  CH, CH
  448.     mov  CL, AL
  449.     jcxz @empty      { FIX for null length string }
  450.     @upperLoop:
  451.     lodsb
  452.     cmp  AL, 'a'
  453.     jb   @cont
  454.     cmp  AL, 'z'
  455.     ja   @cont
  456.     sub  AL, ' '
  457.     @cont:
  458.     stosb
  459.     loop @UpperLoop
  460.     @empty:
  461.     pop  DS
  462.   END;
  463.  
  464.  
  465. procedure vretrace; assembler; { vertical retrace }
  466. asm
  467.   mov dx,3dah
  468.  @vert1:
  469.   in al,dx
  470.   test al,8
  471.   jz @vert1
  472.  @vert2:
  473.   in al,dx
  474.   test al,8
  475.   jnz @vert2
  476. end;
  477.  
  478. Procedure Setupsc(Col, Row, ScrollSize : Word; Var ScreenLoc : Pointer);
  479. Var Seg1, Ofs1 : Word;
  480. Begin
  481.    {I guess we're assuming an 80 column text mode }
  482.    Ofs1 := (Row-1)*160 + ((Col-1)*2);
  483.  
  484.    If (Mem[$40:$49] = 7) then Seg1 := $B000
  485.      else Seg1 := $B800;
  486.  
  487.    ScreenLoc := Ptr(Seg1,Ofs1);
  488. End;
  489.  
  490.  
  491.  
  492. {▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄}
  493. FUNCTION Get_svar: Byte ;
  494. VAR
  495.   CH: Char;
  496.   no_svar: Boolean;
  497.  
  498. BEGIN
  499.   no_svar := TRUE;
  500.   REPEAT
  501.     CH := UpCase (ReadKey);
  502.     IF CH = NullKey THEN
  503.     BEGIN
  504.       CASE Ord (ReadKey) OF
  505.         dnarrow:
  506.                 BEGIN
  507.                   get_svar := dnarrow;
  508.                 END;
  509.         uparrow:
  510.                 BEGIN
  511.                   get_svar := uparrow;
  512.                 END;
  513.         lfarrow:
  514.                 BEGIN
  515.                   get_svar := lfarrow;
  516.                 END;
  517.         rtarrow:
  518.                 BEGIN
  519.                   get_Svar := rtarrow;
  520.                 END;
  521.       END;
  522.     END
  523.     ELSE
  524.       CASE CH OF
  525.         EnterKey  :
  526.                    BEGIN
  527.                      get_svar := 100;
  528.                    END;
  529.  
  530.         EscapeKey :
  531.                    BEGIN
  532.                      get_svar := 27;
  533.                    END;
  534.       END;
  535.  
  536.   UNTIL no_svar <> FALSE;
  537. END;
  538.  
  539.  
  540.  
  541. Procedure Update;Assembler;
  542. ASM
  543.    CLD
  544.    LES  DI, ScreenLoc
  545.    MOV  CX, ScrollSize
  546.  
  547.    MOV  SI, CurrIndex
  548.    OR   SI, SI
  549.    JZ   @WriteString
  550.  
  551.    DEC  CX
  552. @ShiftLeft:
  553.    MOV  AL, ES:[DI+2]
  554.    STOSB
  555.    INC  DI
  556.    LOOP @ShiftLeft
  557.  
  558.    MOV  AL, CS:[SI]
  559.    OR   AL, AL
  560.    JNZ  @NotEndOfStr
  561.    MOV  SI, Offset @Message
  562.    MOV  AL, CS:[SI]
  563. @NotEndOfStr:
  564.    STOSB
  565.  
  566.    INC  SI
  567.    JMP  @SaveIndex
  568.  
  569. @WriteString:
  570.    MOV  SI, Offset @Message
  571. @NextChar:
  572.    MOV  AL, CS:[SI]
  573.    OR   AL, AL
  574.    JZ   @WriteString
  575.    STOSB
  576.    INC  DI
  577.    INC  SI
  578.    LOOP @NextChar
  579.  
  580. @SaveIndex:
  581.    MOV  CurrIndex, SI
  582.    JMP  @Exit
  583.  
  584. @Message:
  585.    DB '                                                   '
  586.    DB '                                                   '
  587.    DB   '(\/)ini  HELP!                        '
  588.    DB '           Function keys available:'
  589.    DB   '      PgUP : One track up      ...      PgDN : One track down '
  590.    DB  '     ...      "." : Pick a track using arrow keys      ...      '
  591.    DB 'RightArrow : FastForward      ...      LeftArrow : Rewind      ...     '
  592.    DB 'If you have a Sound Blaster you can use the "+" & "-" keys to control '
  593.    DB 'the volume.....       '
  594.    DB   0                              { terminate it with NULL       }
  595. @Exit:
  596. End;
  597.  
  598. procedure help;
  599. Var Fedup : Boolean;
  600. time:byte;
  601. c:byte;
  602. emptystr:string;
  603. i:integer;
  604. Begin
  605.    fillchar(emptystr,80,' ');
  606.    emptystr[0]:=#80;
  607.    ScrollSize := 80;
  608.    Setupsc(01,wherey,SCrollSize,ScreenLoc);
  609.    CurrIndex := 0;
  610.    time:=0;
  611.    fedup:=false;
  612.    textcolor(lightgray);
  613.    gotoxy(1,wherey);
  614.    write(emptystr);
  615.    while keypressed do readkey;
  616.    Repeat
  617.      waitforretrace;
  618.      Update;
  619.      if keypressed then
  620.      begin
  621.        c:=get_svar;
  622.        if c=uparrow then inc(time);
  623.        if c=dnarrow then dec(time);
  624.        Fedup := (c = 27);
  625.      end;
  626.    Until (Fedup);
  627. End;
  628.  
  629.  
  630. {▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄}
  631. FUNCTION IntToStr (I: LongInt): String;
  632. {Converts any integer type to a string}
  633. VAR
  634.   S: String [11];
  635. BEGIN
  636.   Str (I, S);
  637.   IntToStr := S;
  638. END;
  639.  
  640.  
  641. {▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄}
  642. PROCEDURE ShowVolume;
  643. var
  644. i:byte;
  645. BEGIN
  646.     gotoxy(33,wherey);
  647.     TEXTCOLOR (DarkGray);
  648.     FOR i := 1 TO 32 DO
  649.     BEGIN
  650.       WRITE ('■');
  651.     END;
  652.  
  653.     TEXTCOLOR (Yellow);
  654.     GOTOXY (33, wherey);
  655.     FOR i := 1 TO lvolume DIV 8 DO
  656.     BEGIN
  657.       WRITE ('▐');
  658.     END;
  659. vol_time:=readtimer;
  660. toslet:=true;
  661. END;
  662.  
  663. {▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄}
  664. PROCEDURE Cursoff;
  665. { Turns the cursor off.  Stores its format for later redisplaying}
  666. BEGIN
  667.   ASM
  668.     Mov AH, 03H
  669.     Mov BH, 00H
  670.     Int 10H
  671.     Mov Crstyp, CX
  672.     Mov AH, 01H
  673.     Mov CX, 65535
  674.     Int 10H
  675.   END;
  676. END;
  677.  
  678.  
  679. {▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄}
  680. PROCEDURE Curson;
  681. {Turns the cursor back on, using the cursor display previously stored}
  682. BEGIN
  683.   ASM
  684.     Mov AH, 01H
  685.     Mov CX, Crstyp
  686.     Int 10H
  687.   END;
  688. END;
  689.  
  690.  
  691.  
  692. {▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄}
  693. PROCEDURE SetColor (Color, Red, Green, Blue : Byte);
  694. {Sets the RGB-values for a given color}
  695. BEGIN
  696.   port [$3C8] := Color;
  697.   port [$3C9] := Red;
  698.   port [$3C9] := Green;
  699.   port [$3C9] := Blue;
  700. END;
  701.  
  702.  
  703. {▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄}
  704. PROCEDURE GetColor (Nr: Byte; VAR R, G, B: Byte);
  705. {Retrieves the RGB-values for a given color}
  706. BEGIN
  707.   Port [$3C7] := Nr;
  708.   R := Port [$3C9];
  709.   G := Port [$3C9];
  710.   B := Port [$3C9];
  711. END;
  712.  
  713.  
  714.  
  715. {▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄}
  716. PROCEDURE wait_4_refresh; ASSEMBLER;
  717. {Waits for the monitors vertical retrace}
  718. LABEL
  719.   wait, retr;
  720. ASM
  721.   mov  DX, 3DAh
  722.   wait:  IN   AL, DX
  723.   Test AL, 08h
  724.   jz   wait
  725.   retr:  IN   AL, DX
  726.   Test AL, 08h
  727.   jnz  retr
  728. END;
  729.  
  730.  
  731.  
  732.  
  733.  
  734. {▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄}
  735. FUNCTION ISCOLOR : Boolean;
  736. {Returns FALSE for MONO or TRUE for COLOR}
  737. VAR
  738.   regs  : Registers;
  739.   video_mode : Integer;
  740.   equ_lo : Byte;
  741. BEGIN
  742.   Intr ($11, regs);
  743.   video_mode := regs. AL AND $30;
  744.   video_mode := video_mode SHR 4;
  745.   CASE video_mode OF
  746.     1 : ISCOLOR := FALSE; { Monochrome }
  747.     2 : ISCOLOR := TRUE{ Color }
  748.   END
  749. END;
  750.  
  751.  
  752.  
  753. {▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄}
  754. PROCEDURE SAVESCR ( VAR screen );
  755. {Saves the screen in an array of bytes}
  756. VAR
  757.   vidc : Byte ABSOLUTE $B800: 0000;
  758.   vidm : Byte ABSOLUTE $B000: 0000;
  759. BEGIN
  760.   IF NOT ISCOLOR THEN { if MONO }
  761.     Move (vidm, screen, 6000)
  762.   ELSE { else COLOR }
  763.     Move (vidc, screen, 6000)
  764. END;
  765.  
  766.  
  767.  
  768. {▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄}
  769. PROCEDURE RESTORESCR ( VAR screen );
  770. {Restores the screen previous stored in an array of bytes}
  771. VAR
  772.   vidc : Byte ABSOLUTE $B800: 0000;
  773.   vidm : Byte ABSOLUTE $B000: 0000;
  774. BEGIN
  775.   IF NOT ISCOLOR THEN { if MONO }
  776.     Move (screen, vidm, 6000)
  777.   ELSE { else COLOR }
  778.     Move (screen, vidc, 6000)
  779. END;
  780.  
  781.  
  782.  
  783. {▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄}
  784. PROCEDURE working;
  785. {Displays an 'working'-status on the screen}
  786. VAR
  787.   X, Y: Byte;
  788.   c: Byte;
  789. BEGIN
  790.   IF playing THEN
  791.   BEGIN
  792.     X := WhereX;
  793.     Y := WhereY;
  794.     c := TextAttr;
  795.  
  796.     TextBackground (Blue);
  797.     TextColor (Black);
  798.     GotoXY (70, 3);
  799.     IF arbejder = 1 THEN Write ('');
  800.     IF arbejder = 2 THEN Write ('');
  801.     IF arbejder = 3 THEN Write ('');
  802.     IF arbejder = 4 THEN Write ('');
  803.  
  804.     IF arbejder < 4 THEN Inc (arbejder)
  805.     ELSE
  806.       arbejder := 1;
  807.     GotoXY (X, Y);
  808.     TextAttr := c;
  809.   END;
  810. END;
  811.  
  812.  
  813. {▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄}
  814. PROCEDURE center (s: String; Y: Byte);
  815. {Centers a given string on a given line on the screen}
  816. BEGIN
  817.   GotoXY (40 - (Length (s) DIV 2), Y);
  818.   Write (s);
  819. END;
  820. {▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄}
  821. Function hex(a : Word; b : Byte) : String;
  822. Const digit : Array[$0..$F] Of Char = '0123456789ABCDEF';
  823. Var i : Byte;
  824.   xstring : String;
  825. Begin
  826.   xstring:='';
  827.   For i:=1 To b Do
  828.   Begin
  829.     Insert(digit[a And $000F], xstring, 1);
  830.     a:=a ShR 4
  831.   End;
  832.   hex:=xstring
  833. End; {hex}
  834.  
  835. {▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄}
  836. Procedure SoundPort;
  837. Var xbyte1, xbyte2, xbyte3, xbyte4: Byte;
  838.   xword, xword1, xword2, temp, sbport: Word;
  839.  
  840. Begin
  841.   sbfound:=False;
  842.   xbyte1:=1;
  843.   While (xbyte1 < 7) And (Not sbfound) Do
  844.   Begin
  845.     sbport:=$200 + ($10 * xbyte1);
  846.     xword1:=0;
  847.     portok:=False;
  848.     While (xword1 < $201) And (Not portok) Do
  849.     Begin
  850.       If (Port[sbport + $0C] And $80) = 0 Then
  851.         portok:=True;
  852.       Inc(xword1)
  853.     End;
  854.     If portok Then
  855.     Begin
  856.       xbyte3:=Port[sbport + $0C];
  857.       Port[sbport + $0C]:=$D3;
  858.       For xword2:=1 To $1000 Do {nothing};
  859.       xbyte4:=Port[sbport + 6];
  860.       Port[sbport + 6]:=1;
  861.       xbyte2:=Port[sbport + 6];
  862.       xbyte2:=Port[sbport + 6];
  863.       xbyte2:=Port[sbport + 6];
  864.       xbyte2:=Port[sbport + 6];
  865.       Port[sbport + 6]:=0;
  866.       xbyte2:=0;
  867.       Repeat
  868.         xword1:=0;
  869.         portok:=False;
  870.         While (xword1 < $201) And (Not portok) Do
  871.         Begin
  872.           If (Port[sbport + $0E] And $80) = $80 Then
  873.             portok:=True;
  874.           Inc(xword1)
  875.         End;
  876.         If portok Then
  877.           If Port[sbport + $0A] = $AA Then
  878.             sbfound:=True;
  879.         Inc(xbyte2);
  880.       Until (xbyte2 = $10) Or (portok);
  881.       If Not portok Then
  882.       Begin
  883.         Port[sbport + $0C]:=xbyte3;
  884.         Port[sbport + 6]:=xbyte4;
  885.       End;
  886.     End;
  887.     If sbfound Then
  888.     Begin
  889.     End
  890.     Else
  891.       Inc(xbyte1);
  892.   End;
  893. End;
  894.  
  895.  
  896. {▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄}
  897. FUNCTION pickatrack: Byte;
  898. {Displays the user with a list of tracks to pick}
  899. VAR
  900.   Top, Bottom  : Byte;
  901.   change      : Boolean; {scroller vi op/ned?}
  902.   slut        : Boolean;
  903.   i           : Byte;
  904.   c           : Byte;
  905.   curr        : Byte;
  906.   index       : Byte;
  907.   s: String;
  908.   topl: Byte;
  909. BEGIN
  910.   topl := wherey-1; {topline}
  911.  
  912.   pickatrack := 0;
  913.   s := '                         ';
  914.   change := FALSE;
  915.   curr  := 1;
  916.   slut  := FALSE;
  917.   Top   := 1;
  918.   index := endtrack;
  919.  
  920.  
  921.   TextColor (lightgray);
  922.   gotoxy(32,topl+1);
  923.   write('Select                           ');
  924.  
  925.   gotoxy(42,topl+1);
  926.   write( '   │      ');
  927.  
  928.   curr:=track;
  929.   REPEAT
  930.   BEGIN
  931.     TextBackground (Black);
  932.     TextColor (lightgray);
  933.     FOR i := Top TO Bottom DO
  934.     BEGIN
  935.       GotoXY (43, topl + 1);
  936.       Write (' ');
  937.       IF i = track THEN
  938.       BEGIN
  939.         TextColor (lightgray+ Blink);
  940.         Write (leadingzero (i) );
  941.         TextColor (lightgray);
  942.         Write ('│');
  943.         TextColor (lightgray+ Blink);
  944.         Write (leadingzero (trackinfo [i]^. playmin) );
  945.         TextColor (lightgray);
  946.         Write (':');
  947.         TextColor (lightgray+ Blink);
  948.         Write (leadingzero (trackinfo [i]^. playsec) );
  949.       END
  950.       ELSE
  951.       BEGIN
  952.         Write (leadingzero (i) );
  953.         Write ('│');
  954.         Write (leadingzero (trackinfo [i]^. playmin) );
  955.         Write (':');
  956.         Write (leadingzero (trackinfo [i]^. playsec) );
  957.       END;
  958.     END;
  959.     IF curr = track THEN
  960.     BEGIN
  961.       TextColor (lightgray);
  962.       GotoXY (44, topl +  1);
  963.       Write (leadingzero (curr) );
  964.       TextColor (lightgray);
  965.       Write ('│');
  966.       TextColor (lightgray);
  967.       Write (leadingzero (trackinfo [curr]^. playmin) );
  968.       TextColor (lightgray);
  969.       Write (':');
  970.       TextColor (lightgray);
  971.       Write (leadingzero (trackinfo [curr]^. playsec) );
  972.     END
  973.     ELSE
  974.     BEGIN
  975.       TextColor (lightgray);
  976.       GotoXY (44, topl +  1);
  977.       Write (leadingzero (curr) );
  978.       Write ('│');
  979.       Write (leadingzero (trackinfo [curr]^. playmin) );
  980.       Write (':');
  981.       Write (leadingzero (trackinfo [curr]^. playsec) );
  982.     END;
  983.     textbackground(black);
  984.     textcolor(lightgray);
  985.     gotoxy(39,topl+1);
  986.  
  987.     if curr=1 then write('( )');
  988.     if curr=index then write('( )');
  989.     if ((curr<index) and (Curr>1)) then write('()');
  990.  
  991.     repeat
  992.       calctrack;
  993.       q_channel_info;
  994.       textcolor(yellow);
  995.       gotoxy(18,wherey);
  996.       write(leadingzero(track));
  997.       gotoxy(21,wherey);
  998.       textcolor(white);
  999.       write(leadingzero(endtrack));
  1000.       textcolor(yellow);
  1001.       gotoxy(24,wherey);
  1002.       write(leadingzero(qchannelinfo.minutes));
  1003.       gotoxy(27,wherey);
  1004.       write(leadingzero(qchannelinfo.seconds));
  1005.     until keypressed;
  1006.  
  1007.  
  1008.     c := get_Svar;
  1009.  
  1010.  
  1011.     IF (c = uparrow) THEN
  1012.     BEGIN
  1013.       IF (curr = Top) AND (Top > 1) THEN
  1014.       BEGIN
  1015.         Dec (Top);
  1016.         Dec (curr);
  1017.         change := TRUE;
  1018.       END;
  1019.       IF (curr > Top) THEN Dec (curr);
  1020.     END;
  1021.     IF (c = dnarrow) THEN
  1022.     BEGIN
  1023.       IF (curr < index)THEN
  1024.       begin
  1025.         Inc (curr);
  1026.         inc(top);
  1027.       end;
  1028.     END;
  1029.     IF c = 100 THEN
  1030.     BEGIN
  1031.       pickatrack := curr;
  1032.       slut := TRUE;
  1033.     END;
  1034.     IF c = 27 THEN
  1035.     BEGIN
  1036.       TextBackground (Black);
  1037.       gotoxy(32,topl+1);write('                     ');
  1038.       Exit;
  1039.     END;
  1040.   END; {while}
  1041.   UNTIL slut;
  1042.   TextBackground (Black);
  1043.   gotoxy(32,topl+1);write('                       ');
  1044. END;
  1045.  
  1046.  
  1047.  
  1048. {▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄}
  1049. PROCEDURE colwrite (col, startline: Byte; s: String);
  1050. {Writes a given line downwards from the given column and the given startline}
  1051. VAR
  1052. i, j: Byte;
  1053. BEGIN
  1054.   j := 1;
  1055.   FOR i := startline TO startline+ Length (s) - 1 DO
  1056.   BEGIN
  1057.     GotoXY (col, i);
  1058.     Write (s [j] );
  1059.     Inc (j);
  1060.   END;
  1061. END;
  1062.  
  1063.  
  1064.  
  1065.  
  1066. {▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄}
  1067. PROCEDURE stuffthebuff;
  1068. {Empties the buffer}
  1069. VAR
  1070.   chartoskip: Char;
  1071.  
  1072. BEGIN
  1073.   WHILE KeyPressed DO
  1074.     chartoskip := ReadKey;
  1075. END;
  1076.  
  1077.  
  1078. {▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄}
  1079. FUNCTION Get_Scan_Code : Word;
  1080. VAR
  1081.   HTregs : Registers;
  1082. BEGIN
  1083.   HTregs. AH := $01;
  1084.   Intr ($16, HTregs);
  1085.   Get_Scan_Code := HTregs. AX;
  1086. END;
  1087.  
  1088.  
  1089.  
  1090.  
  1091. {▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄}
  1092. PROCEDURE fuckthebuff;
  1093. {Flushes the keyboard-buffer}
  1094. BEGIN
  1095.   ASM
  1096.     Mov AX, $0C00;
  1097.     Int 21h;
  1098.   END;
  1099.  
  1100. END;
  1101.  
  1102.  
  1103. {▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄}
  1104. {▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄}
  1105. {▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄}
  1106. {▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄}
  1107. {▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄}
  1108. {▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄}
  1109. {▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄}
  1110. {▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄}
  1111. {▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄}
  1112. VAR
  1113.   currtrack    : Byte;
  1114.   ieren        : LongInt;
  1115.   slut         : Boolean;
  1116.   newtrack     : Byte;
  1117.   xkor,
  1118.   ykor         : Byte;
  1119.   timepassed:longint;
  1120. BEGIN
  1121.   origmode     := LastMode;
  1122.   cursoff;
  1123.   soundport;
  1124.   port [$224] := 48;
  1125.   lvolume := port [$225];
  1126.   port [$224] := 49;
  1127.   rvolume := port [$225];
  1128.   port [$224] := 65;
  1129.  
  1130.  
  1131.   xkor         := WhereX;
  1132.   ykor         := WhereY;
  1133.   TextColor (LightGray);
  1134.   TextBackground (Black);
  1135.  
  1136.   gotoxy(1,wherey-1);
  1137.   textcolor(white);
  1138.   write('(\/)ini');
  1139.   textcolor(lightgray);
  1140.   writeln('  v.1   Checking CD-ROM ... ');
  1141.  
  1142.   gotoxy(1,wherey);
  1143.   Audio_Disk_Info;
  1144.   Setup;
  1145.  
  1146.   IF AudioDiskInfo. HighestTrack < 1 THEN
  1147.   BEGIN
  1148.     delay(200);
  1149.     Audio_Disk_Info;
  1150.     Setup;
  1151.     WriteLn ('Not an audio-CD!');
  1152.     curson;
  1153.     Exit;
  1154.   END;
  1155.  
  1156.   gotoxy(1,wherey-1);
  1157.  
  1158.   gotoxy(01,wherey);
  1159.   write('(\/)ini  v.1     xx/xx xx:XX                                           L/th 1996');
  1160.   gotoxy(1,wherey-1);
  1161.  
  1162.  
  1163.   gotoxy(18,wherey);
  1164.   slut := FALSE;
  1165.  
  1166.   textcolor(white);
  1167.  
  1168.   audio_status_info;
  1169.   q_channel_info;
  1170.   audio_status_info;
  1171.   audio_disk_info;
  1172.   Play_Audio (trackinfo [starttrack]^. startpoint, trackinfo [endtrack]^. endpoint);
  1173.  
  1174.  
  1175.   REPEAT
  1176.     REPEAT
  1177.       if toslet then
  1178.       begin
  1179.         if elapsedtime(vol_time,readtimer)>700 then
  1180.         begin
  1181.           gotoxy(33,wherey);
  1182.           write('                                ');
  1183.           toslet:=false;
  1184.         end;
  1185.       end;
  1186.  
  1187.       fuckthebuff;
  1188.       calctrack;
  1189.       q_channel_info;
  1190.       gotoxy(18,wherey);
  1191.       write(leadingzero(track));
  1192.       gotoxy(21,wherey);
  1193.       textcolor(white);
  1194.       write(leadingzero(endtrack));
  1195.       textcolor(yellow);
  1196.       gotoxy(24,wherey);
  1197.       write(leadingzero(qchannelinfo.minutes));
  1198.       gotoxy(27,wherey);
  1199.       write(leadingzero(qchannelinfo.seconds));
  1200.     UNTIL InKey (Hi, Hi2);
  1201.  
  1202.     {ESC (EXIT AUDIO)}
  1203.     IF ( (Hi = 1) AND (Hi2 = 27) )  THEN slut := TRUE;
  1204.  
  1205.     {Page Up (UP ONE TRACK)}
  1206.     IF ( (Hi = 73) AND ( (Hi2 = 0) OR (Hi2 = 224) ) AND (playing) AND (track < endtrack) ) THEN
  1207.     BEGIN
  1208.       pause_audio;
  1209.       play_audio (trackinfo [track + 1]^. startpoint, trackinfo [endtrack]^. endpoint);
  1210.     END;
  1211.  
  1212.     {Page Down (DOWN ONE TRACK)}
  1213.     IF ( (Hi = 81) AND ( (Hi2 = 0) OR (Hi2 = 224) ) AND (playing) AND (track > starttrack) ) THEN
  1214.     BEGIN
  1215.       IF ( (place < (trackinfo [track]^. startpoint + 3000) ) ) THEN
  1216.       BEGIN
  1217.         pause_audio;
  1218.         play_audio (trackinfo [track - 1]^. startpoint, trackinfo [endtrack]^. endpoint);
  1219.       END;
  1220.       IF ( (place > (trackinfo [track]^. startpoint + 3000) ) ) THEN
  1221.       BEGIN
  1222.         pause_audio;
  1223.         play_audio (trackinfo [track]^. startpoint, trackinfo [endtrack]^. endpoint);
  1224.       END;
  1225.     END;
  1226.  
  1227.     {Right Arrow (SKIP 3-4 SECS)}
  1228.     IF ( (Hi = 77) AND ( (Hi2 = 0) OR (Hi2 = 224) ) AND (playing) AND ( (place+ (3000) ) <
  1229.        trackinfo [endtrack]^. endpoint) )
  1230.     THEN
  1231.     BEGIN
  1232.       pause_audio;
  1233.       play_audio (place+1000, trackinfo [endtrack]^. endpoint);
  1234.     END;
  1235.  
  1236.     {Left Arrow (SKIP 3-4 SECS)}
  1237.     IF ( (Hi = 75) AND ( (Hi2 = 0) OR (Hi2 = 224) ) AND (playing) AND ( (place- (3000 * 4) ) >
  1238.        trackinfo [starttrack]^. startpoint) )
  1239.     THEN
  1240.     BEGIN
  1241.       pause_audio;
  1242.       play_audio ((place- 1000), trackinfo [endtrack]^. endpoint);
  1243.       delay(20);
  1244.     END;
  1245.  
  1246.     {Middle key (PAUSE/RESUME)}
  1247.     IF ( (Hi = 76) AND (Hi2 = 0) ) THEN
  1248.     BEGIN
  1249.       IF playing THEN
  1250.       BEGIN
  1251.         io_control (stopplay);
  1252.         audio_status_info;
  1253.       END
  1254.       ELSE
  1255.       BEGIN
  1256.         resume_play;
  1257.       END;
  1258.     END;
  1259.  
  1260.     IF ( (Hi = 52) AND (Hi2 = 46) ) THEN
  1261.     BEGIN
  1262.       newtrack := pickatrack;
  1263.       IF newtrack > 0 THEN
  1264.       BEGIN
  1265.         pause_audio;
  1266.         play_audio (trackinfo [newtrack]^. startpoint, trackinfo [endtrack]^. endpoint);
  1267.       END;
  1268.     END;
  1269.  
  1270.     {HELP MENU!}
  1271.     IF ( (Hi = 59) AND (Hi2 = 0) ) THEN
  1272.     BEGIN
  1273.       fuckthebuff;
  1274.       help;
  1275.       gotoxy(01,wherey-1);
  1276.       write('(\/)ini  v.1     xx/xx xx:XX                                           L/th 1996');
  1277.       gotoxy(1,wherey-1);
  1278.     END;
  1279.  
  1280.  
  1281.  
  1282. { VOLUME-CONTROL!}
  1283.  
  1284. {'-' (Reduce BOTH volumes)}
  1285.     IF ( (Hi = 74) AND (Hi2 = 45) AND NOT ( (left_shift) OR (right_shift) ) ) THEN
  1286.     BEGIN
  1287.       if sbfound then
  1288.       begin
  1289.         IF rvolume > 04 THEN
  1290.         BEGIN
  1291.           DEC (rvolume, 4);
  1292.           port [$224] := 49;
  1293.           port [$225] := rvolume;
  1294.         END;
  1295.         IF lvolume > 04 THEN
  1296.         BEGIN
  1297.           DEC (lvolume, 4);
  1298.           port [$224] := 48;
  1299.           port [$225] := lvolume;
  1300.         END;
  1301.         showvolume;
  1302.       end;
  1303.     END;
  1304.  
  1305.  
  1306. {'+' (Increase BOTH volumes)}
  1307.     IF ( (Hi = 78) AND (Hi2 = 43) AND NOT ( (left_shift) OR (right_shift) ) ) THEN
  1308.     BEGIN
  1309.       if sbfound then
  1310.       begin
  1311.         IF rvolume < 252 THEN
  1312.         BEGIN
  1313.           INC (rvolume, 4);
  1314.           port [$224] := 49;
  1315.           port [$225] := rvolume;
  1316.         END;
  1317.         IF lvolume < 252 THEN
  1318.         BEGIN
  1319.           INC (lvolume, 4);
  1320.           port [$224] := 48;
  1321.           port [$225] := lvolume;
  1322.         END;
  1323.         showvolume;
  1324.       end;
  1325.     END;
  1326.  
  1327. { VOLUME-CONTROL!}
  1328.    stuffthebuff;
  1329.   UNTIL slut;
  1330. gotoxy(1,wherey);
  1331. textcolor(lightgray);
  1332. writeln('(\/)ini  v.1     Mini-CD-ROM-player                                    L/th 1996');
  1333. curson;
  1334. END.
  1335.  
  1336.  
  1337. {CUT OFF ...}
  1338.  
  1339. {CUT ... Save this as CD_UNIT.PAS}
  1340. UNIT CD_Unit;
  1341.  
  1342. INTERFACE
  1343.  
  1344. USES DOS, CD_Vars;
  1345.  
  1346. VAR
  1347.   Drive   : Integer;  { Must set drive before all operations }
  1348.   SubUnit : Integer;
  1349.   
  1350. PROCEDURE IO_Control (Command : Byte);
  1351. FUNCTION File_Name (VAR Code : Integer) : String;
  1352.  
  1353. FUNCTION Read_VTOC (VAR VTOC : VTOCArray;
  1354.                    VAR Index : Integer) : Boolean;
  1355.  
  1356. PROCEDURE CD_Check (VAR Code : Integer);
  1357.  
  1358. PROCEDURE Vol_Desc (VAR Code : Integer;
  1359.                    VAR ErrCode : Integer);
  1360.  
  1361. PROCEDURE CD_Dev_Req (DevPointer : Pointer);
  1362.  
  1363. PROCEDURE Get_Dir_Entry (PathName : String;
  1364.                         VAR Format, ErrCode : Integer);
  1365.  
  1366. PROCEDURE DeviceStatus;
  1367.  
  1368. PROCEDURE Audio_Channel_Info;
  1369.  
  1370. PROCEDURE Audio_Disk_Info;
  1371.  
  1372. PROCEDURE Audio_Track_Info (VAR StartPoint : LongInt;
  1373.                            VAR TrackControl : Byte);
  1374.  
  1375. PROCEDURE Audio_Status_Info;
  1376.  
  1377. PROCEDURE Q_Channel_Info;
  1378.  
  1379. PROCEDURE Lock (LockDrive : Boolean);
  1380.  
  1381. PROCEDURE Resetcd;
  1382.  
  1383. PROCEDURE Eject;
  1384.  
  1385. PROCEDURE CloseTray;
  1386.  
  1387. PROCEDURE Resume_Play;
  1388.  
  1389. PROCEDURE Pause_Audio;
  1390.  
  1391. PROCEDURE Play_Audio (StartSec, EndSec : LongInt);
  1392.  
  1393. FUNCTION Sector_Size (ReadMode : Integer) : Word;
  1394.  
  1395. FUNCTION Volume_Size : LongInt;
  1396.  
  1397. FUNCTION Media_Changed : Boolean;
  1398.  
  1399. FUNCTION Head_Location (AddrMode : Byte) : LongInt;
  1400.  
  1401. PROCEDURE Read_Drive_Bytes (VAR ReadBytes : DriveByteArray);
  1402.  
  1403. PROCEDURE Read_Long (TransAddr : Pointer; StartSec : LongInt);
  1404.  
  1405. PROCEDURE SeekSec (StartSec : LongInt);
  1406.  
  1407. PROCEDURE DevClose;
  1408.  
  1409. PROCEDURE DevOpen;
  1410.  
  1411. PROCEDURE OutputFlush;
  1412.  
  1413. PROCEDURE InputFlush;
  1414.  
  1415. FUNCTION UPC_Code : String;
  1416.  
  1417. IMPLEMENTATION
  1418.  
  1419. CONST
  1420.   CarryFlag  = $0001;
  1421.  
  1422. TYPE
  1423.   PointerHalf = RECORD
  1424.                   LoHalf, HiHalf : Word;
  1425.                 END;
  1426.   
  1427. VAR
  1428.   Regs       : Registers;
  1429.   IOBlock    : IOControl;
  1430.   DriveBytes : ARRAY [1..130] OF Byte;
  1431.   
  1432. PROCEDURE Clear_Regs;
  1433. BEGIN
  1434.   FillChar (Regs, SizeOf (Regs), #0);
  1435. END;
  1436.  
  1437. PROCEDURE CD_Intr;
  1438. BEGIN
  1439.   Regs. AH := $15;
  1440.   Intr ($2F, Regs);
  1441. END;
  1442.  
  1443. PROCEDURE MSCDEX_Ver;
  1444. BEGIN
  1445.   Clear_Regs;
  1446.   Regs. AL := $0C;
  1447.   Regs. BX := $0000;
  1448.   CD_Intr;
  1449.   MSCDEX_Version. Minor := 0;
  1450.   IF Regs. BX = 0 THEN
  1451.     MSCDEX_Version. Major := 1
  1452.   ELSE
  1453.   BEGIN
  1454.     MSCDEX_Version. Major := Regs. BH;
  1455.     MSCDEX_Version. Minor := Regs. BL;
  1456.   END;
  1457. END;
  1458.  
  1459. PROCEDURE Initialize;
  1460. BEGIN
  1461.   NumberOfCD := 0;
  1462.   Clear_Regs;
  1463.   Regs. AL := $00;
  1464.   Regs. BX := $0000;
  1465.   CD_Intr;
  1466.   IF Regs. BX <> 0 THEN
  1467.   BEGIN
  1468.     NumberOfCD := Regs. BX;
  1469.     FirstCD := Regs. CX;
  1470.     Clear_Regs;
  1471.     FillChar (DriverList, SizeOf (DriverList), #0);
  1472.     FillChar (UnitList, SizeOf (UnitList), #0);
  1473.     Regs. AL := $01;               { Get List of Driver Header Addresses }
  1474.     Regs. ES := Seg (DriverList);
  1475.     Regs. BX := Ofs (DriverList);
  1476.     CD_Intr;
  1477.     Clear_Regs;
  1478.     Regs. AL := $0D;               { Get List of CD-ROM Units }
  1479.     Regs. ES := Seg (UnitList);
  1480.     Regs. BX := Ofs (UnitList);
  1481.     CD_Intr;
  1482.     MSCDEX_Ver;
  1483.   END;
  1484. END;
  1485.  
  1486.  
  1487. FUNCTION File_Name (VAR Code : Integer) : String;
  1488. VAR
  1489.   FN : String [38];
  1490. BEGIN
  1491.   Clear_Regs;
  1492.   Regs. AL := Code + 1;
  1493.   {
  1494.   Copyright Filename     =  1
  1495.   Abstract Filename      =  2
  1496.   Bibliographic Filename =  3
  1497.   }
  1498.   Regs. CX := Drive;
  1499.   Regs. ES := Seg (FN);
  1500.   Regs. BX := Ofs (FN);
  1501.   CD_Intr;
  1502.   Code := Regs. AX;
  1503.   IF (Regs. Flags AND CarryFlag) = 0 THEN
  1504.     File_Name := FN
  1505.   ELSE
  1506.     File_Name := '';
  1507. END;
  1508.  
  1509.  
  1510. FUNCTION Read_VTOC (VAR VTOC : VTOCArray;
  1511.                    VAR Index : Integer) : Boolean;
  1512. { On entry -
  1513.      Index = Vol Desc Number to read from 0 to ?
  1514.   On return
  1515.      Case Index of
  1516.             1    : Standard Volume Descriptor
  1517.             $FF  : Volume Descriptor Terminator
  1518.             0    : All others
  1519. }
  1520. BEGIN
  1521.   Clear_Regs;
  1522.   Regs. AL := $05;
  1523.   Regs. CX := Drive;
  1524.   Regs. DX := Index;
  1525.   Regs. ES := Seg (VTOC);
  1526.   Regs. BX := Ofs (VTOC);
  1527.   CD_Intr;
  1528.   Index := Regs. AX;
  1529.   IF (Regs. Flags AND CarryFlag) = 0 THEN
  1530.     Read_VTOC := TRUE
  1531.   ELSE
  1532.     Read_VTOC := FALSE;
  1533. END;
  1534.  
  1535. PROCEDURE CD_Check (VAR Code : Integer);
  1536. BEGIN
  1537.   Clear_Regs;
  1538.   Regs. AL := $0B;
  1539.   Regs. BX := $0000;
  1540.   Regs. CX := Drive;
  1541.   CD_Intr;
  1542.   IF Regs. BX <> $ADAD THEN
  1543.     Code := 2
  1544.   ELSE
  1545.   BEGIN
  1546.     IF Regs. AX <> 0 THEN
  1547.       Code := 0
  1548.     ELSE
  1549.       Code := 1;
  1550.   END;
  1551. END;
  1552.  
  1553.  
  1554. PROCEDURE Vol_Desc (VAR Code : Integer;
  1555.                    VAR ErrCode : Integer);
  1556.  
  1557.   FUNCTION Get_Vol_Desc : Byte;
  1558.     BEGIN
  1559.       Clear_Regs;
  1560.       Regs. CX := Drive;
  1561.       Regs. AL := $0E;
  1562.       Regs. BX := $0000;
  1563.       CD_Intr;
  1564.       Code := Regs. AX;
  1565.       IF (Regs. Flags AND CarryFlag) <> 0 THEN
  1566.         ErrCode := $FF;
  1567.       Get_Vol_Desc := Regs. DH;
  1568.     END;
  1569.  
  1570. BEGIN
  1571.   Clear_Regs;
  1572.   ErrCode := 0;
  1573.   IF Code <> 0 THEN
  1574.   BEGIN
  1575.     Regs. DH := Code;
  1576.     Regs. DL := 0;
  1577.     Regs. BX := $0001;
  1578.     Regs. AL := $0E;
  1579.     Regs. CX := Drive;
  1580.     CD_Intr;
  1581.     Code := Regs. AX;
  1582.     IF (Regs. Flags AND CarryFlag) <> 0 THEN
  1583.       ErrCode := $FF;
  1584.   END;
  1585.   IF ErrCode = 0 THEN
  1586.     Code := Get_Vol_Desc;
  1587. END;
  1588.  
  1589. PROCEDURE Get_Dir_Entry (PathName : String;
  1590.                         VAR Format, ErrCode : Integer);
  1591. BEGIN
  1592.   FillChar (DirBuf, SizeOf (DirBuf), #0);
  1593.   PathName := PathName + #0;
  1594.   Clear_Regs;
  1595.   Regs. AL := $0F;
  1596.   Regs. CL := Drive;
  1597.   Regs. CH := 1;
  1598.   Regs. ES := Seg (PathName);
  1599.   Regs. BX := Ofs (PathName);
  1600.   Regs. SI := Seg (DirBuf);
  1601.   Regs. DI := Ofs (DirBuf);
  1602.   CD_Intr;
  1603.   ErrCode := Regs. AX;
  1604.   IF (Regs. Flags AND CarryFlag) = 0 THEN
  1605.   BEGIN
  1606.     Move (DirBuf. NameArray [1], DirBuf. FileName [1], 38);
  1607.     DirBuf. FileName [0] := #12; { File names are only 8.3 }
  1608.     Format := Regs. AX
  1609.   END
  1610.   ELSE
  1611.     Format := $FF;
  1612. END;
  1613.  
  1614. PROCEDURE CD_Dev_Req (DevPointer : Pointer);
  1615. BEGIN
  1616.   Clear_Regs;
  1617.   Regs. AL := $10;
  1618.   Regs. CX := Drive;
  1619.   Regs. ES := PointerHalf (DevPointer).HiHalf;
  1620.   Regs. BX := PointerHalf (DevPointer).LoHalf;
  1621.   CD_Intr;
  1622. END;
  1623.  
  1624. PROCEDURE IO_Control (Command : Byte);
  1625. BEGIN
  1626.   IOBlock. IOReq_Hdr. Len := 26;
  1627.   IOBlock. IOReq_Hdr. SubUnit := SubUnit;
  1628.   IOBlock. IOReq_Hdr. Status := 0;
  1629.   IOBlock. TransAddr := @DriveBytes;
  1630.   IOBlock. IOReq_Hdr. Command := Command;
  1631.   
  1632.   FillChar (IOBlock. IOReq_Hdr. Reserved, 8, #0);
  1633.   
  1634.   CD_Dev_Req (@IOBlock);
  1635.   
  1636.   Busy :=   (IOBlock. IOReq_Hdr. Status AND 512) <> 0;
  1637.   
  1638.   
  1639. END;
  1640.  
  1641. PROCEDURE Audio_Channel_Info;
  1642. BEGIN
  1643.   FillChar (DriveBytes, SizeOf (DriveBytes), #0);
  1644.   DriveBytes [1] := 4;
  1645.   IOBlock. NumBytes := 9;
  1646.   
  1647.   IO_Control (IOCtlInput);
  1648.   
  1649.   Move (DriveBytes, AudioChannel, 9);
  1650. END;
  1651.  
  1652. PROCEDURE DeviceStatus;
  1653. BEGIN
  1654.   FillChar (DriveBytes, SizeOf (DriveBytes), #0);
  1655.   
  1656.   DriveBytes [1] := 6;
  1657.   IOBlock. NumBytes := 5;
  1658.   
  1659.   IO_Control (IOCtlInput);
  1660.   
  1661.   DoorOpen     := DriveBytes [2] AND 1 <> 0;
  1662.   DoorLocked   := DriveBytes [2] AND 2 <> 0;
  1663.   AudioManip   := DriveBytes [3] AND 1 <> 0;
  1664.   DiscInDrive  := DriveBytes [3] AND 8 <> 0;
  1665.   
  1666. END;
  1667.  
  1668. PROCEDURE Audio_Disk_Info;
  1669. BEGIN
  1670.   FillChar (DriveBytes, SizeOf (DriveBytes), #0);
  1671.   
  1672.   DriveBytes [1] := 10;
  1673.   IOBlock. NumBytes := 7;
  1674.   
  1675.   IO_Control (IOCtlInput);
  1676.   
  1677.   Move (DriveBytes [2], AudioDiskInfo, 6);
  1678.   
  1679.   Playing := Busy;
  1680.   
  1681. END;
  1682.  
  1683. PROCEDURE Audio_Track_Info (VAR StartPoint : LongInt;
  1684.                            VAR TrackControl : Byte);
  1685. BEGIN
  1686.   FillChar (DriveBytes, SizeOf (DriveBytes), #0);
  1687.  
  1688.   DriveBytes [1] := 11;
  1689.   DriveBytes [2] := TrackControl;   { Track number }
  1690.   IOBlock. NumBytes := 7;
  1691.   
  1692.   IO_Control (IOCtlInput);
  1693.   
  1694.   Move (DriveBytes [3], StartPoint, 4);
  1695.   
  1696.   TrackControl := DriveBytes [7];
  1697.   
  1698.   Playing := Busy;
  1699. END;
  1700.  
  1701. PROCEDURE Q_Channel_Info;
  1702. BEGIN
  1703.   FillChar (DriveBytes, SizeOf (DriveBytes), #0);
  1704.   
  1705.   DriveBytes [1] := 12;
  1706.   IOBlock. NumBytes := 11;
  1707.   
  1708.   IO_Control (IOCtlInput);
  1709.   
  1710.   Move (DriveBytes [2], QChannelInfo, 11);
  1711.   
  1712. END;
  1713.  
  1714. PROCEDURE Audio_Status_Info;
  1715. BEGIN
  1716.   FillChar (DriveBytes, SizeOf (DriveBytes), #0);
  1717.   
  1718.   DriveBytes [1] := 15;
  1719.   IOBlock. NumBytes := 11;
  1720.   
  1721.   IO_Control (IOCtlInput);
  1722.   
  1723.   Paused := (Word (DriveBytes [2] ) AND 1) <> 0;
  1724.   
  1725.   Move (DriveBytes [4], Last_Start, 4);
  1726.   Move (DriveBytes [8], Last_End, 4);
  1727.   
  1728.   Playing := Busy;
  1729. END;
  1730.  
  1731. PROCEDURE Eject;
  1732. BEGIN
  1733.   FillChar (DriveBytes, SizeOf (DriveBytes), #0);
  1734.   
  1735.   DriveBytes [1] := 0;
  1736.   IOBlock. NumBytes := 1;
  1737.   
  1738.   IO_Control (IOCtlOutput);
  1739. END;
  1740.  
  1741. PROCEDURE Resetcd;
  1742. BEGIN
  1743.   FillChar (DriveBytes, SizeOf (DriveBytes), #0);
  1744.  
  1745.   DriveBytes [1] := 2;
  1746.   IOBlock. NumBytes := 1;
  1747.   
  1748.   IO_Control (IOCtlOutput);
  1749.   Busy := TRUE;
  1750. END;
  1751.  
  1752. PROCEDURE Lock (LockDrive : Boolean);
  1753. BEGIN
  1754.   FillChar (DriveBytes, SizeOf (DriveBytes), #0);
  1755.   
  1756.   DriveBytes [1] := 1;
  1757.   IF LockDrive THEN
  1758.     DriveBytes [2] := 1
  1759.   ELSE
  1760.     DriveBytes [2] := 0;
  1761.   IOBlock. NumBytes := 2;
  1762.   
  1763.   IO_Control (IOCtlOutput);
  1764. END;
  1765.  
  1766. PROCEDURE CloseTray;
  1767. BEGIN
  1768.   FillChar (DriveBytes, SizeOf (DriveBytes), #0);
  1769.   
  1770.   DriveBytes [1] := 5;
  1771.   IOBlock. NumBytes := 1;
  1772.   
  1773.   IO_Control (IOCtlOutput);
  1774. END;
  1775.  
  1776. VAR
  1777.   AudioPlay : Audio_Play;
  1778.   
  1779. FUNCTION Play (StartLoc, NumSec : LongInt) : Boolean;
  1780. BEGIN
  1781.   FillChar (AudioPlay, SizeOf (AudioPlay), #0);
  1782.   AudioPlay. APReq. Command := PlayCD;
  1783.   AudioPlay. APReq. Len := 22;
  1784.   AudioPlay. APReq. SubUnit := SubUnit;
  1785.   AudioPlay. Start := StartLoc;
  1786.   AudioPlay. NumSecs := NumSec;
  1787.   AudioPlay. AddrMode := 1;
  1788.   
  1789.   CD_Dev_Req (@AudioPlay);
  1790.   Play := ( (AudioPlay. APReq. Status AND 32768) = 0);
  1791.   
  1792. END;
  1793.  
  1794. PROCEDURE Play_Audio (StartSec, EndSec : LongInt);
  1795. VAR
  1796.   SP,
  1797.   EP     : LongInt;
  1798.   SArray : ARRAY [1..4] OF Byte;
  1799.   EArray : ARRAY [1..4] OF Byte;
  1800. BEGIN
  1801.   Move (StartSec, SArray [1], 4);
  1802.   Move (EndSec, EArray [1], 4);
  1803.   SP := SArray [3];           { Must use longint or get negative result }
  1804.   SP := (SP * 75 * 60) + (SArray [2] * 75) + SArray [1];
  1805.   EP := EArray [3];
  1806.   EP := (EP * 75 * 60) + (EArray [2] * 75) + EArray [1];
  1807.   EP := EP - SP;
  1808.   
  1809.   Playing := Play (StartSec, EP);
  1810.   Audio_Status_Info;
  1811. END;
  1812.  
  1813. PROCEDURE Pause_Audio;
  1814. BEGIN
  1815.   IF Playing THEN
  1816.   BEGIN
  1817.     FillChar (AudioPlay, SizeOf (AudioPlay), #0);
  1818.     AudioPlay. APReq. Command := stopplay; {stopplay}
  1819.     AudioPlay. APReq. Len := 13;
  1820.     AudioPlay. APReq. SubUnit := SubUnit;
  1821.     CD_Dev_Req (@AudioPlay);
  1822.   END;
  1823.   Audio_Status_Info;
  1824.   Playing := FALSE;
  1825. END;
  1826.  
  1827. PROCEDURE Resume_Play;
  1828. BEGIN
  1829.   FillChar (AudioPlay, SizeOf (AudioPlay), #0);
  1830.   AudioPlay. APReq. Command := ResumePlay;
  1831.   AudioPlay. APReq. Len := 13;
  1832.   AudioPlay. APReq. SubUnit := SubUnit;
  1833.   CD_Dev_Req (@AudioPlay);
  1834.   Audio_Status_Info;
  1835. END;
  1836.  
  1837. FUNCTION Sector_Size (ReadMode : Integer) : Word;
  1838. VAR SecSize : Word;
  1839. BEGIN
  1840.   FillChar (DriveBytes, SizeOf (DriveBytes), #0);
  1841.   
  1842.   DriveBytes [1] := 7;
  1843.   DriveBytes [2] := ReadMode;
  1844.   
  1845.   IOBlock. NumBytes := 4;
  1846.   
  1847.   IO_Control (IOCtlInput);
  1848.   
  1849.   Move (DriveBytes [3], SecSize, 2);
  1850.   Sector_Size := SecSize;
  1851. END;
  1852.  
  1853. (*Function CD_GetVol:Boolean;
  1854. begin
  1855.   CtlBlk[0] := 4;                           { die Lautstaerke lesen }
  1856.   CD_GetVol := CD_IOCtl(IoCtlRead, 8);
  1857.   if ((R.Flags and FCARRY) = 0)
  1858.    then Move(CtlBlk[1], CD.VolInfo, 8)
  1859.    else FillChar( CD.VolInfo, 8, 0)
  1860. end;
  1861.  
  1862. Function CD_SetVol:Boolean;
  1863. begin
  1864.   CtlBlk[0] := 3;                          { die Lautstaerke setzen }
  1865.   CD_SetVol := CD_IOCtl( IoCtlWrite, 8);
  1866. end;
  1867. *)
  1868.  
  1869. FUNCTION Volume_Size : LongInt;
  1870. VAR VolSize : LongInt;
  1871. BEGIN
  1872.   FillChar (DriveBytes, SizeOf (DriveBytes), #0);
  1873.   
  1874.   DriveBytes [1] := 8;
  1875.   
  1876.   IOBlock. NumBytes := 5;
  1877.  
  1878.   IO_Control (IOCtlInput);
  1879.   
  1880.   Move (DriveBytes [2], VolSize, 4);
  1881.   Volume_Size := VolSize;
  1882. END;
  1883.  
  1884. FUNCTION Media_Changed : Boolean;
  1885. VAR MedChng : Byte;
  1886.   
  1887.   {  1  :  Media not changed
  1888.   0  :  Don't Know
  1889.   -1  :  Media changed
  1890.   }
  1891. BEGIN
  1892.   FillChar (DriveBytes, SizeOf (DriveBytes), #0);
  1893.   
  1894.   DriveBytes [1] := 9;
  1895.   
  1896.   IOBlock. NumBytes := 2;
  1897.   
  1898.   IO_Control (IOCtlInput);
  1899.   
  1900.   Move (DriveBytes [2], MedChng, 4);
  1901.   Inc (MedChng);
  1902.   CASE MedChng OF
  1903.     2    : Media_Changed := FALSE;
  1904.     1, 0  : Media_Changed := TRUE;
  1905.   END;
  1906. END;
  1907.  
  1908. FUNCTION Head_Location (AddrMode : Byte) : LongInt;
  1909. VAR
  1910.   HeadLoc : LongInt;
  1911. BEGIN
  1912.   FillChar (DriveBytes, SizeOf (DriveBytes), #0);
  1913.   
  1914.   DriveBytes [1] := 1;
  1915.   DriveBytes [2] := AddrMode;
  1916.   
  1917.   IOBlock. NumBytes := 6;
  1918.   
  1919.   IO_Control (IOCtlInput);
  1920.   
  1921.   Move (DriveBytes [3], HeadLoc, 4);
  1922.   Head_Location := HeadLoc;
  1923. END;
  1924.  
  1925. PROCEDURE Read_Drive_Bytes (VAR ReadBytes : DriveByteArray);
  1926. BEGIN
  1927.   FillChar (DriveBytes, SizeOf (DriveBytes), #0);
  1928.   
  1929.   DriveBytes [1] := 5;
  1930.   
  1931.   IOBlock. NumBytes := 130;
  1932.   
  1933.   IO_Control (IOCtlInput);
  1934.  
  1935.   Move (DriveBytes [3], ReadBytes, 128);
  1936. END;
  1937.  
  1938.  
  1939. FUNCTION UPC_Code : String;
  1940. VAR
  1941.   I, J, K : Integer;
  1942.   TempStr : String;
  1943. BEGIN
  1944.   FillChar (DriveBytes, SizeOf (DriveBytes), #0);
  1945.   TempStr := '';
  1946.   DriveBytes [1] := 14;
  1947.   
  1948.   IOBlock. NumBytes := 11;
  1949.   
  1950.   IO_Control (IOCtlInput);
  1951.   
  1952.   IF ( (IOBlock. IOReq_Hdr. Status AND 32768) = 0) THEN;
  1953.   FOR I := 3 TO 9 DO
  1954.   BEGIN
  1955.     J := DriveBytes [I] AND $0F;
  1956.     K := DriveBytes [I] AND $F0;
  1957.     TempStr := TempStr + Chr (J + 48);
  1958.     TempStr := TempStr + Chr (K + 48);
  1959.   END;
  1960.   IF Length (TempStr) > 13 THEN
  1961.     TempStr [0] := Chr (Ord (TempStr [0] ) - 1);
  1962.   UPC_Code := TempStr;
  1963. END;
  1964.  
  1965.  
  1966. PROCEDURE Read_Long (TransAddr : Pointer; StartSec : LongInt);
  1967. VAR
  1968.   RL : ReadControl;
  1969.   {
  1970.   ReadControl = Record
  1971.   IOReq_Hdr : Req_Hdr;
  1972.   AddrMode  : Byte;
  1973.   TransAddr : Pointer;
  1974.   NumSecs   : Word;
  1975.   StartSec  : LongInt;
  1976.   ReadMode  : Byte;
  1977.   IL_Size,
  1978.   IL_Skip   : Byte;
  1979.   End;
  1980.   }
  1981. BEGIN
  1982.   FillChar (RL, SizeOf (RL), #0);
  1983.   RL. IOReq_Hdr. Len := 27;
  1984.   RL. IOReq_Hdr. SubUnit := SubUnit;
  1985.   RL. IOReq_Hdr. Command := ReadLong;
  1986.   RL. AddrMode := 1;
  1987.   RL. TransAddr := TransAddr;
  1988.   RL. NumSecs := 1;
  1989.   RL. StartSec := StartSec;
  1990.   RL. ReadMode := 0;
  1991.   CD_Dev_Req (@RL);
  1992. END;
  1993.  
  1994. PROCEDURE SeekSec (StartSec : LongInt);
  1995. VAR
  1996.   RL : ReadControl;
  1997.   
  1998. BEGIN
  1999.   FillChar (RL, SizeOf (RL), #0);
  2000.   RL. IOReq_Hdr. Len := 24;
  2001.   RL. IOReq_Hdr. SubUnit := SubUnit;
  2002.   RL. IOReq_Hdr. Command := SeekCmd;
  2003.   RL. AddrMode := 1;
  2004.   RL. StartSec := StartSec;
  2005.   RL. ReadMode := 0;
  2006.   CD_Dev_Req (@RL);
  2007. END;
  2008.  
  2009. PROCEDURE InputFlush;
  2010. VAR
  2011.   IOReq : Req_Hdr;
  2012. BEGIN
  2013.   FillChar (IOReq, SizeOf (IOReq), #0);
  2014.   WITH IOReq DO
  2015.   BEGIN
  2016.     Len     := 13;
  2017.     SubUnit := SubUnit;
  2018.     Command := 7;
  2019.     Status  := 0;
  2020.   END;
  2021.   CD_Dev_Req (@IOReq);
  2022. END;
  2023.  
  2024. PROCEDURE OutputFlush;
  2025. VAR
  2026.   IOReq : Req_Hdr;
  2027. BEGIN
  2028.   FillChar (IOReq, SizeOf (IOReq), #0);
  2029.   WITH IOReq DO
  2030.   BEGIN
  2031.     Len     := 13;
  2032.     SubUnit := SubUnit;
  2033.     Command := 11;
  2034.     Status  := 0;
  2035.   END;
  2036.   CD_Dev_Req (@IOReq);
  2037. END;
  2038.  
  2039. PROCEDURE DevOpen;
  2040. VAR
  2041.   IOReq : Req_Hdr;
  2042. BEGIN
  2043.   FillChar (IOReq, SizeOf (IOReq), #0);
  2044.   WITH IOReq DO
  2045.   BEGIN
  2046.     Len     := 13;
  2047.     SubUnit := SubUnit;
  2048.     Command := 13;
  2049.     Status  := 0;
  2050.   END;
  2051.   CD_Dev_Req (@IOReq);
  2052. END;
  2053.  
  2054. PROCEDURE DevClose;
  2055. VAR
  2056.   IOReq : Req_Hdr;
  2057. BEGIN
  2058.   FillChar (IOReq, SizeOf (IOReq), #0);
  2059.   WITH IOReq DO
  2060.   BEGIN
  2061.     Len     := 13;
  2062.     SubUnit := SubUnit;
  2063.     Command := 14;
  2064.     Status  := 0;
  2065.   END;
  2066.   CD_Dev_Req (@IOReq);
  2067. END;
  2068.  
  2069. {************************************************************}
  2070.  
  2071. BEGIN
  2072.   NumberOfCD := 0;
  2073.   FirstCD := 0;
  2074.   FillChar (MSCDEX_Version, SizeOf (MSCDEX_Version), #0);
  2075.   Initialize;
  2076.   Drive := FirstCD;
  2077.   SubUnit := 0;
  2078. END.
  2079.  
  2080. {CUT OFF ...}
  2081.  
  2082. {CUT ... Save this as CD_VARS.PAS}
  2083.  
  2084. UNIT CD_Vars;
  2085.  
  2086. INTERFACE
  2087.  
  2088. TYPE
  2089.   ListBuf    = RECORD
  2090.                  UnitCode : Byte;
  2091.                  UnitSeg,
  2092.                  UnitOfs  : Word;
  2093.                END;
  2094.   VTOCArray  = ARRAY [1..2048] OF Byte;
  2095.   DriveByteArray = ARRAY [1..128] OF Byte;
  2096.   
  2097.   Req_Hdr    = RECORD
  2098.                  Len     : Byte;
  2099.                  SubUnit : Byte;
  2100.                  Command : Byte;
  2101.                  Status  : Word;
  2102.                  Reserved: ARRAY [1..8] OF Byte;
  2103.                END;
  2104.   
  2105. CONST
  2106.   Init       = 0;
  2107.   IoCtlInput = 3;
  2108.   InputFlush = 7;
  2109.   IOCtlOutput = 12;
  2110.   DevOpen    = 13;
  2111.   DevClose   = 14;
  2112.   ReadLong   = 128;
  2113.   ReadLongP  = 130;
  2114.   SeekCmd    = 131;
  2115.   PlayCD     = 132;
  2116.   StopPlay   = 133;
  2117.   ResumePlay = 136;
  2118.   
  2119. TYPE
  2120.   
  2121.   Audio_Play = RECORD
  2122.                  APReq    : Req_Hdr;
  2123.                  AddrMode : Byte;
  2124.                  Start    : LongInt;
  2125.                  NumSecs  : LongInt;
  2126.                END;
  2127.   
  2128.   IOControl = RECORD
  2129.                 IOReq_Hdr : Req_Hdr;
  2130.                 MediaDesc : Byte;
  2131.                 TransAddr : Pointer;
  2132.                 NumBytes  : Word;
  2133.                 StartSec  : Word;
  2134.                 ReqVol    : Pointer;
  2135.               END;
  2136.   
  2137.   ReadControl = RECORD
  2138.                   IOReq_Hdr : Req_Hdr;
  2139.                   AddrMode  : Byte;
  2140.                   TransAddr : Pointer;
  2141.                   NumSecs   : Word;
  2142.                   StartSec  : LongInt;
  2143.                   ReadMode  : Byte;
  2144.                   IL_Size,
  2145.                   IL_Skip   : Byte;
  2146.                 END;
  2147.   
  2148.   AudioDiskInfoRec = RECORD
  2149.                        LowestTrack    : Byte;
  2150.                        HighestTrack   : Byte;
  2151.                        LeadOutTrack   : LongInt;
  2152.                        {new!}
  2153.                        VolInfo: ARRAY [1..8] OF Byte; { Lautst.-Einstellungen }
  2154.                      END;
  2155.   
  2156.   PAudioTrackInfo   = ^AudioTrackInfoRec;
  2157.   AudioTrackInfoRec = RECORD
  2158.                         Track           : Integer;
  2159.                         StartPoint      : LongInt;
  2160.                         EndPoint        : LongInt;
  2161.                         Frames,
  2162.                         Seconds,
  2163.                         Minutes,
  2164.                         PlayMin,
  2165.                         PlaySec,
  2166.                         TrackControl    : Byte;
  2167.                       END;
  2168.   
  2169.   MSCDEX_Ver_Rec = RECORD
  2170.                      Major,
  2171.                      Minor       : Integer;
  2172.                    END;
  2173.   
  2174.   DirBufRec    = RECORD
  2175.                    XAR_Len   : Byte;
  2176.                    FileStart : LongInt;
  2177.                    BlockSize : Integer;
  2178.                    FileLen   : LongInt;
  2179.                    DT        : Byte;
  2180.                    Flags     : Byte;
  2181.                    InterSize : Byte;
  2182.                    InterSkip : Byte;
  2183.                    VSSN      : Integer;
  2184.                    NameLen   : Byte;
  2185.                    NameArray : ARRAY [1..38] OF Char;
  2186.                    FileVer   : Integer;
  2187.                    SysUseLen : Byte;
  2188.                    SysUseData: ARRAY [1..220] OF Byte;
  2189.                    FileName  : String [38];
  2190.                  END;
  2191.   
  2192.   Q_Channel_Rec = RECORD
  2193.                     Control     : Byte;
  2194.                     Track       : Byte;
  2195.                     Index       : Byte;
  2196.                     Minutes     : Byte;
  2197.                     Seconds     : Byte;
  2198.                     Frame       : Byte;
  2199.                     Zero        : Byte;
  2200.                     AMinutes    : Byte;
  2201.                     ASeconds    : Byte;
  2202.                     AFrame      : Byte;
  2203.                   END;
  2204.   
  2205. VAR
  2206.   AudioChannel   : ARRAY [1..9] OF Byte;
  2207.   DoorOpen,
  2208.   DoorLocked,
  2209.   AudioManip,
  2210.   DiscInDrive    : Boolean;
  2211.   AudioDiskInfo  : AudioDiskInfoRec;
  2212.   DriverList     : ARRAY [1..26] OF ListBuf;
  2213.   NumberOfCD     : Integer;
  2214.   FirstCD        : Integer;
  2215.   UnitList       : ARRAY [1..26] OF Byte;
  2216.   MSCDEX_Version : MSCDEX_Ver_Rec;
  2217.   QChannelInfo   : Q_Channel_Rec;
  2218.   Busy,
  2219.   Playing,
  2220.   Paused         : Boolean;
  2221.   Last_Start,
  2222.   Last_End       : LongInt;
  2223.   DirBuf         : DirBufRec;
  2224.   
  2225. IMPLEMENTATION
  2226.  
  2227. BEGIN
  2228.   FillChar (DriverList, SizeOf (DriverList), #0);
  2229.   FillChar (UnitList, SizeOf (UnitList), #0);
  2230.   NumberOfCD  := 0;
  2231.   FirstCD  := 0;
  2232.   MSCDEX_Version. Major := 0;
  2233.   MSCDEX_Version. Minor := 0;
  2234. END.
  2235.  
  2236. {CUT OFF ...}
  2237.  
  2238.  
  2239. {CUT ... Save this as TPTIMER.PAS}
  2240.  
  2241. {$S-,R-,I-,V-,B-}
  2242.  
  2243. {*********************************************************}
  2244. {*                   TPTIMER.PAS 2.00                    *}
  2245. {*                by TurboPower Software                 *}
  2246. {*********************************************************}
  2247.  
  2248. UNIT TpTimer;
  2249.   {-Allows events to be timed with 1 microsecond resolution}
  2250.  
  2251. INTERFACE
  2252.  
  2253. PROCEDURE InitializeTimer;
  2254.   {-Reprogram the timer chip to allow 1 microsecond resolution}
  2255.  
  2256. PROCEDURE RestoreTimer;
  2257.   {-Restore the timer chip to its normal state}
  2258.  
  2259. FUNCTION ReadTimer : LongInt;
  2260.   {-Read the timer with 1 microsecond resolution}
  2261.  
  2262. FUNCTION ElapsedTime (Start, Stop : LongInt) : Real;
  2263.   {-Calculate time elapsed (in milliseconds) between Start and Stop}
  2264.  
  2265. FUNCTION ElapsedTimeString (Start, Stop : LongInt) : String;
  2266.   {-Return time elapsed (in milliseconds) between Start and Stop as a string}
  2267.  
  2268.   {==========================================================================}
  2269.  
  2270. IMPLEMENTATION
  2271.  
  2272. CONST
  2273.   TimerResolution = 1193181.667;
  2274. VAR
  2275.   SaveExitProc : Pointer;
  2276.   Delta : LongInt;
  2277.   
  2278. FUNCTION Cardinal (L : LongInt) : Real;
  2279.     {-Return the unsigned equivalent of L as a real}
  2280.   BEGIN                      {Cardinal}
  2281.     IF L < 0 THEN
  2282.       Cardinal := 4294967296.0 + L
  2283.     ELSE
  2284.       Cardinal := L;
  2285.   END;                       {Cardinal}
  2286.  
  2287.   FUNCTION ElapsedTime (Start, Stop : LongInt) : Real;
  2288.     {-Calculate time elapsed (in milliseconds) between Start and Stop}
  2289.   BEGIN                      {ElapsedTime}
  2290.     ElapsedTime := 1000.0 * Cardinal (Stop - (Start + Delta) ) / TimerResolution;
  2291.   END;                       {ElapsedTime}
  2292.  
  2293.   FUNCTION ElapsedTimeString (Start, Stop : LongInt) : String;
  2294.     {-Return time elapsed (in milliseconds) between Start and Stop as a string}
  2295.   VAR
  2296.     R : Real;
  2297.     S : String;
  2298.   BEGIN                      {ElapsedTimeString}
  2299.     R := ElapsedTime (Start, Stop);
  2300.     Str (R: 0: 3, S);
  2301.     ElapsedTimeString := S;
  2302.   END;                       {ElapsedTimeString}
  2303.  
  2304.   PROCEDURE InitializeTimer;
  2305.     {-Reprogram the timer chip to allow 1 microsecond resolution}
  2306.   BEGIN                      {InitializeTimer}
  2307.     {select timer mode 2, read/write channel 0}
  2308.     Port [$43] := $34;        {00110100b}
  2309.     INLINE ($EB / $00);         {jmp short $+2 ;delay}
  2310.     Port [$40] := $00;        {LSB = 0}
  2311.     INLINE ($EB / $00);         {jmp short $+2 ;delay}
  2312.     Port [$40] := $00;        {MSB = 0}
  2313.   END;                       {InitializeTimer}
  2314.  
  2315.   PROCEDURE RestoreTimer;
  2316.     {-Restore the timer chip to its normal state}
  2317.   BEGIN                      {RestoreTimer}
  2318.     {select timer mode 3, read/write channel 0}
  2319.     Port [$43] := $36;        {00110110b}
  2320.     INLINE ($EB / $00);         {jmp short $+2 ;delay}
  2321.     Port [$40] := $00;        {LSB = 0}
  2322.     INLINE ($EB / $00);         {jmp short $+2 ;delay}
  2323.     Port [$40] := $00;        {MSB = 0}
  2324.   END;                       {RestoreTimer}
  2325.  
  2326.   FUNCTION ReadTimer : LongInt;
  2327.     {-Read the timer with 1 microsecond resolution}
  2328.   BEGIN                      {ReadTimer}
  2329.     INLINE (
  2330.     $FA /                   {cli             ;Disable interrupts}
  2331.     $BA / $20 / $00 /           {mov  dx,$20     ;Address PIC ocw3}
  2332.     $B0 / $0A /               {mov  al,$0A     ;Ask to read irr}
  2333.     $EE /                   {out  dx,al}
  2334.     $B0 / $00 /               {mov  al,$00     ;Latch timer 0}
  2335.     $E6 / $43 /               {out  $43,al}
  2336.     $EC /                   {in   al,dx      ;Read irr}
  2337.     $89 / $C7 /               {mov  di,ax      ;Save it in DI}
  2338.     $E4 / $40 /               {in   al,$40     ;Counter --> bx}
  2339.     $88 / $C3 /               {mov  bl,al      ;LSB in BL}
  2340.     $E4 / $40 /               {in   al,$40}
  2341.     $88 / $C7 /               {mov  bh,al      ;MSB in BH}
  2342.     $F7 / $D3 /               {not  bx         ;Need ascending counter}
  2343.     $E4 / $21 /               {in   al,$21     ;Read PIC imr}
  2344.     $89 / $C6 /               {mov  si,ax      ;Save it in SI}
  2345.     $B0 / $FF /               {mov  al,$0FF    ;Mask all interrupts}
  2346.     $E6 / $21 /               {out  $21,al}
  2347.     $B8 / $40 / $00 /           {mov  ax,$40     ;read low word of time}
  2348.     $8E / $C0 /               {mov  es,ax      ;from BIOS data area}
  2349.     $26 / $8B / $16 / $6C / $00 /   {mov  dx,es:[$6C]}
  2350.     $89 / $F0 /               {mov  ax,si      ;Restore imr from SI}
  2351.     $E6 / $21 /               {out  $21,al}
  2352.     $FB /                   {sti             ;Enable interrupts}
  2353.     $89 / $F8 /               {mov  ax,di      ;Retrieve old irr}
  2354.     $A8 / $01 /               {test al,$01     ;Counter hit 0?}
  2355.     $74 / $07 /               {jz   done       ;Jump if not}
  2356.     $81 / $FB / $FF / $00 /       {cmp  bx,$FF     ;Counter > $FF?}
  2357.     $77 / $01 /               {ja   done       ;Done if so}
  2358.     $42 /                   {inc  dx         ;Else count int req.}
  2359.     {done:}
  2360.     $89 / $5E / $FC /           {mov [bp-4],bx   ;set function result}
  2361.     $89 / $56 / $FE);          {mov [bp-2],dx}
  2362.   END;                       {ReadTimer}
  2363.  
  2364.   PROCEDURE Calibrate;
  2365.     {-Calibrate the timer}
  2366.   CONST
  2367.     Reps = 1000;
  2368.   VAR
  2369.     I : Word;
  2370.     L1, L2, Diff : LongInt;
  2371.   BEGIN                      {Calibrate}
  2372.     Delta := MaxInt;
  2373.     FOR I := 1 TO Reps DO BEGIN
  2374.       L1 := ReadTimer;
  2375.       L2 := ReadTimer;
  2376.       {use the minimum difference}
  2377.       Diff := L2 - L1;
  2378.       IF Diff < Delta THEN
  2379.         Delta := Diff;
  2380.     END;
  2381.   END;                       {Calibrate}
  2382.  
  2383.   {$F+}
  2384.   PROCEDURE OurExitProc;
  2385.     {-Restore timer chip to its original state}
  2386.   BEGIN                      {OurExitProc}
  2387.     ExitProc := SaveExitProc;
  2388.     RestoreTimer;
  2389.   END;                       {OurExitProc}
  2390.   {$F-}
  2391.  
  2392. BEGIN
  2393.   {set up our exit handler}
  2394.   SaveExitProc := ExitProc;
  2395.   ExitProc := @OurExitProc;
  2396.   
  2397.   {reprogram the timer chip}
  2398.   InitializeTimer;
  2399.   
  2400.   {adjust for speed of machine}
  2401.   Calibrate;
  2402. END.
  2403.  
  2404.  
  2405. {CUT OFF...}
  2406.  
  2407.  
  2408. {CUT ... Save this as TCTIMER.PAS}
  2409.  
  2410. UNIT tctimer;
  2411.  
  2412. INTERFACE
  2413. USES tptimer;
  2414.  
  2415.   VAR
  2416.     start : LongInt;
  2417.     
  2418.   PROCEDURE StartTimer;
  2419.  
  2420. PROCEDURE WriteElapsedTime;
  2421.  
  2422.  
  2423.  
  2424. IMPLEMENTATION
  2425.  
  2426. PROCEDURE StartTimer;
  2427.   BEGIN
  2428.     start := ReadTimer;
  2429.   END;
  2430.  
  2431. PROCEDURE  WriteElapsedTime;
  2432.   VAR stop : LongInt;
  2433.   BEGIN
  2434.     stop := ReadTimer;
  2435.     WriteLn ('calc = ', (ElapsedTime (start, stop) / 1000): 10: 6, ' sec');
  2436.   END;
  2437.  
  2438.  
  2439. END.
  2440.  
  2441. {CUT OFF...}
  2442.  
  2443. {CUT ... Save this as TPBUFFER.PAS}
  2444.  
  2445. UNIT TPbuffer;
  2446.  
  2447. (* TP-Buffer unit version 1.1 /Update              *)
  2448. (* Using the keyboard's buffer in Turbo Pascal     *)
  2449. (* This unit is released to the public domain      *)
  2450. (* by Lavi Tidhar on 5-10-1992                     *)
  2451.  
  2452. (* This unit adds three special functions not      *)
  2453. (* incuded in the Turbo Pascal regular package     *)
  2454.  
  2455. (* You may alter this source code, move the        *)
  2456. (* procedures to your own programs. Please do      *)
  2457. (* NOT change these lines of documentation         *)
  2458.  
  2459. (* This source might teach you about how to        *)
  2460. (* use interrupts in pascal, and the keyboard's    *)
  2461. (* buffer. from the other hand, it might not :-)   *)
  2462.  
  2463. (* Used: INT 16, functions 0 and 1                 *)
  2464. (*       INT 21, function 0Ch                      *)
  2465.  
  2466. (* INT 16 - KEYBOARD - READ CHAR FROM BUFFER, WAIT IF EMPTY
  2467.            AH = 00h
  2468.            Return: AH = scan code
  2469.                    AL = character         *)
  2470.  
  2471. (* INT 16 - KEYBOARD - CHECK BUFFER, DO NOT CLEAR
  2472.            AH = 01h
  2473.            Return: ZF = 0 character in buffer
  2474.                        AH = scan code
  2475.                        AL = character
  2476.                        ZF = 1 no character in buffer *)
  2477.  
  2478. (* INT 21 - DOS - CLEAR KEYBOARD BUFFER
  2479.         AH = 0Ch
  2480.         AL must be 1, 6, 7, 8, or 0Ah.
  2481.         Notes: Flushes all typeahead input, then executes function specified by AL
  2482.         (effectively moving it to AH and repeating the INT 21 call).
  2483.         If AL contains a value not in the list above, the keyboard buffer is
  2484.         flushed and no other action is taken. *)
  2485.  
  2486. (* For more details/help etc, you can contact me on: *)
  2487.  
  2488. (* Mail: Lavi Tidhar
  2489.          46 Bantam Dr.
  2490.          Blairgowrie
  2491.          2194
  2492.          South Africa
  2493. *)
  2494.  
  2495. (* Phone:
  2496.           International: +27-11-787-8093
  2497.           South Africa:  (011)-787-8093
  2498. *)
  2499.  
  2500. (* Netmail: The Catacomb BBS 5:7101/45 (fidonet)
  2501.             The Catacomb BBS 80:80/100 (pipemail)
  2502. *)
  2503.  
  2504. INTERFACE
  2505.  
  2506. USES DOS;
  2507.  
  2508. FUNCTION GetScanCode: Byte; (* Get SCAN CODE from buffer, wait if empty *)
  2509. FUNCTION GetKey: Char;      (* Get Char from buffer, do NOT wait *)
  2510. PROCEDURE FlushKB;
  2511.  
  2512. IMPLEMENTATION
  2513.  
  2514. FUNCTION GetKey: Char;
  2515.  VAR Regs: Registers;
  2516.  BEGIN
  2517.    Regs. AH := 1;                (* Int 16 function 1 *)
  2518.    Intr ($16, Regs);           (* Read a charecter from the keyboard buffer *)
  2519.    GetKey := Chr (Regs. AL);     (* do not wait. If no char was found, CHR(0) *)
  2520.  END;                        (* (nul) is returned *)
  2521.  
  2522. FUNCTION GetScanCode: Byte;   (* Int 16 function 0 *)
  2523.  VAR Regs: Registers;         (* The same as CRT's Readkey, but gives you *)
  2524.  BEGIN                      (* the scan code. Esp usefull when you want to *)
  2525.    Regs. AH := 1;               (* use special keys as the arrows, there will *)
  2526.    Intr ($16, Regs);          (* be a conflict when using ReadKey *)
  2527.    GetScanCode := Regs. AH;
  2528.  END;
  2529.  
  2530. PROCEDURE FlushKB;           (* INT 21 function 0C *)
  2531.  VAR Regs: Registers;         (* Flushes (erase) the keyboard buffer *)
  2532.  BEGIN                      (* ONLY. No other function is executed *)
  2533.    Regs. AH := $0C;
  2534.    Regs. AL := 2;
  2535.    Intr ($21, Regs);
  2536.  END;
  2537.  
  2538. END.
  2539.  
  2540. {CUT OFF...}
  2541.  
  2542.  
  2543. {CUT... Save this as SCANCODE.PAS}
  2544.  
  2545. UNIT ScanCode;
  2546.  
  2547. { This UNIT is created by Wayne Boyd, aka Vipramukhya Swami, BBS phone
  2548.    (604)431-6260, Fidonet node 1:153/763. It's function is to facilitate
  2549.    the use of Function keys and Alt keys in a program. It includes F1
  2550.    through F10, Shift-F1 through Shift-F10, Ctrl-F1 through Ctrl-F10,
  2551.    and Alt-F1 through Alt-F10. It also includes all of the alt keys, all
  2552.    of the Ctrl keys and many other keys as well. This UNIT and source code
  2553.    are copyrighted material and may not be used for commercial use
  2554.    without express written permission from the author. Use at your own
  2555.    risk. I take absolutely no responsibility for it, and there are no
  2556.    guarantees that it will do anything more than take up space on your
  2557.    disk. }
  2558.  
  2559.  
  2560. INTERFACE
  2561.  
  2562. CONST
  2563.   
  2564.   F1  = 59;   CtrlF1  =  94;   AltF1  = 104;   Homekey   = 71;
  2565.   F2  = 60;   CtrlF2  =  95;   AltF2  = 105;   Endkey    = 79;
  2566.   F3  = 61;   CtrlF3  =  96;   AltF3  = 106;   PgUp      = 73;
  2567.   F4  = 62;   CtrlF4  =  97;   AltF4  = 107;   PgDn      = 81;
  2568.   F5  = 63;   CtrlF5  =  98;   AltF5  = 108;   UpArrow   = 72;
  2569.   F6  = 64;   CtrlF6  =  99;   AltF6  = 109;   RtArrow   = 77;
  2570.   F7  = 65;   CtrlF7  = 100;   AltF7  = 110;   DnArrow   = 80;
  2571.   F8  = 66;   CtrlF8  = 101;   AltF8  = 111;   LfArrow   = 75;
  2572.   F9  = 67;   CtrlF9  = 102;   AltF9  = 112;   InsertKey = 82;
  2573.   F10 = 68;   CtrlF10 = 103;   AltF10 = 113;   DeleteKey = 83;
  2574.   
  2575.   AltQ = 16;   AltA = 30;   AltZ = 44;   Alt1 = 120;  ShftF1 = 84;
  2576.   AltW = 17;   AltS = 31;   AltX = 45;   Alt2 = 121;  ShftF2 = 85;
  2577.   AltE = 18;   AltD = 32;   AltC = 46;   Alt3 = 122;  ShftF3 = 86;
  2578.   AltR = 19;   AltF = 33;   AltV = 47;   Alt4 = 123;  ShftF4 = 87;
  2579.   AltT = 20;   AltG = 34;   AltB = 48;   Alt5 = 124;  ShftF5 = 88;
  2580.   AltY = 21;   AltH = 35;   AltN = 49;   Alt6 = 125;  ShftF6 = 89;
  2581.   AltU = 22;   AltJ = 36;   AltM = 50;   Alt7 = 126;  ShftF7 = 90;
  2582.   AltI = 23;   AltK = 37;                Alt8 = 127;  ShftF8 = 91;
  2583.   AltO = 24;   AltL = 38;                Alt9 = 128;  ShftF9 = 92;
  2584.   AltP = 25;   CtrlLf = 115;             Alt0 = 129;  ShftF10 = 93;
  2585.   CtrlRt = 116;
  2586.   
  2587.   CtrlA  = #1;  CtrlK = #11; CtrlU = #21; CtrlB = #2;  CtrlL = #12;
  2588.   CtrlV  = #22; CtrlC = #3;  CtrlM = #13; CtrlW = #23; CtrlD = #4;
  2589.   CtrlN  = #14; CtrlX = #24; CtrlE = #5;  CtrlO = #15; CtrlY = #25;
  2590.   CtrlF  = #6;  CtrlP = #16; CtrlZ = #26; CtrlG = #7;  CtrlQ = #17;
  2591.   CtrlS  = #19; CtrlH = #8;  CtrlR = #18; CtrlI = #9;  CtrlJ = #10;
  2592.   CtrlT = #20;  BSpace = #8; EscapeKey = #27; EnterKey = #13; NullKey = #0;
  2593.   
  2594. IMPLEMENTATION
  2595.  
  2596. END.
  2597.  
  2598. {CUT OFF...}
  2599.